
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>JVM学习指南 - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>JVM学习指南 - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">概念</div>
          <div class="card-question">JDK、JRE 和 JVM 之间存在怎样的关系？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">概念</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">JDK (Java Development Kit) 包含了 JRE (Java Runtime Environment) 和开发工具（如编译器、调试器）。JRE 包含了 JVM (Java Virtual Machine) 和 Java 核心类库。因此，它们的关系是：JDK > JRE > JVM。JDK 用于开发，而 JRE 是运行 Java 程序所必需的环境。</div>
          </div>
          <div class="card-source">来源: Java中的基本概念</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">体系结构</div>
          <div class="card-question">JVM 的运行时数据区主要包含哪些部分？请区分线程共享和线程私有的区域。</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">体系结构</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">JVM 的运行时数据区主要包括方法区、虚拟机栈、本地方法栈、程序计数器和堆。其中，堆和方法区是所有线程共享的区域；而虚拟机栈、本地方法栈和程序计数器是线程私有的，生命周期与线程相同。</div>
          </div>
          <div class="card-source">来源: JVM体系结构, Java内存模型</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">与 JDK 1.7 的永久代相比，JDK 1.8 的元空间（Metaspace）最大的区别是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">元空间与永久代之间最大的区别在于：元空间并不在虚拟机中，而是使用本地内存（Native Memory）。因此，默认情况下，元空间的大小仅受本地内存的限制，而永久代是堆内存的一部分，有固定大小。</div>
          </div>
          <div class="card-source">来源: 1.7和1.8对比</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">请解释什么是 Java 的双亲委派机制？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">双亲委派机制是指当一个类加载器需要加载某个 .class 文件时，它首先会把这个任务委托给它的上级类加载器，这个操作会递归进行。只有当上级类加载器无法加载该类时，当前类加载器才会自己尝试去加载。如果最终也加载不到，则会抛出 ClassNotFoundException 异常。</div>
          </div>
          <div class="card-source">来源: 类加载器 / 双亲委派机制</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">采用双亲委派机制进行类加载主要有哪些好处？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">双亲委派机制主要有两个好处：1. 避免类的重复加载，因为父加载器已经加载过的类，子加载器无需再次加载。2. 保证了 Java 核心 API 的安全，防止核心 API 类被用户自定义的同名类所篡改。</div>
          </div>
          <div class="card-source">来源: 类加载器 / 双亲委派机制的好处</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">概念</div>
          <div class="card-question">内存泄露（Memory Leak）和内存溢出（Out of Memory）有何不同？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">概念</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">内存泄露指的是程序中动态开辟的空间在使用完毕后未能被释放，导致它一直占据内存单元直到程序结束。内存溢出（OOM）则是指程序在申请内存时，没有足够的内存空间供其使用。内存泄露的长期累积可能会最终导致内存溢出。</div>
          </div>
          <div class="card-source">来源: 内存泄露, 内存溢出</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">简述一个新创建的对象在 JVM 堆区中从新生代晋升到老年代的典型过程。</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">一个新对象首先在新生代的伊甸园区（Eden）创建。当伊甸园满时触发 Minor GC，存活的对象会被移到幸存者0区。当幸存者0区也满时，存活对象会被移到幸存者1区。对象在幸存者区之间每经历一次 Minor GC 年龄就加一，当年龄达到15次后，如果对象依然存活，就会被晋升到老年代。</div>
          </div>
          <div class="card-source">来源: 堆区 / GC回收过程</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">什么是 JVM 的逃逸分析技术？它能带来什么主要的性能优化？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">逃逸分析是分析对象动态作用域的技术。如果 JVM 通过逃逸分析确定一个对象不会“逃逸”出方法之外（即只在方法内部使用），它就可以进行优化。主要的优化是进行“栈上分配”，即将对象直接在栈上分配内存，而不是在堆上。这样，对象占用的内存可以随栈帧出栈而自动销毁，从而减轻垃圾回收（GC）的压力。</div>
          </div>
          <div class="card-source">来源: 逃逸分析 / JVM内存逃逸分析</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">体系结构</div>
          <div class="card-question">Java 虚拟机栈中的“栈帧”是什么？在虚拟机栈中可能发生哪两种主要的异常？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">体系结构</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">虚拟机栈描述的是 Java 方法执行的内存模型。每个方法在执行时都会创建一个栈帧，用于存储局部变量表、操作数栈、动态链接、方法出口等信息。一个方法的调用到完成，就对应一个栈帧在虚拟机栈中的入栈到出栈过程。可能发生的两种异常是：StackOverflowError（线程请求的栈深度大于允许深度）和 OutOfMemoryError（虚拟机栈扩展时无法申请到足够内存）。</div>
          </div>
          <div class="card-source">来源: JVM体系结构 / 虚拟机栈</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
